package player;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

import javax.media.Codec;
import javax.media.ConfigureCompleteEvent;
import javax.media.ControllerEvent;
import javax.media.ControllerListener;
import javax.media.DataSink;
import javax.media.EndOfMediaEvent;
import javax.media.Manager;
import javax.media.MediaLocator;
import javax.media.NoDataSinkException;
import javax.media.NoPlayerException;
import javax.media.PrefetchCompleteEvent;
import javax.media.Processor;
import javax.media.RealizeCompleteEvent;
import javax.media.UnsupportedPlugInException;
import javax.media.control.TrackControl;
import javax.media.datasink.DataSinkEvent;
import javax.media.datasink.DataSinkListener;
import javax.media.datasink.EndOfStreamEvent;
import javax.media.format.VideoFormat;
import javax.media.protocol.DataSource;
import javax.media.protocol.FileTypeDescriptor;


public class MySaveProcessor implements ControllerListener, DataSinkListener {
	Processor mySaveProcessor = null;
	java.io.File urlString = null;
	java.net.URL urlSource = null;
	
	private DataSource videoSource = null;
	private DataSink save = null;
	private MediaLocator savingPlace = null;

	public MyEffect myEffect;
	public MyBrightness myBrightness;
	
	/**
	 * @author Michael Kascha 0548800
	 * constructor for the processor, depening on the source
	 */
	public MySaveProcessor(String urlString, MediaLocator videoDestination, MyEffect myEffect, MyBrightness myBrightness) {
		savingPlace = videoDestination;
		this.myEffect = myEffect;
		this.myBrightness = myBrightness;
		// URL Source
		if (urlString.startsWith("http")) {
			try {
				urlSource = new URL (urlString);
				// System.out.println("Processor with url source");
				initializeWithURL();
			}
			catch (MalformedURLException e) { }
		}
		// File Source
		else {
			this.urlString = new java.io.File(urlString);
			// System.out.println("Processor with file source");
			initializeWithFile();
		}
	}
	
	/**
	 * @author Michael Kascha 0548800
	 * set up the processor with a local file as source
	 */
	public void initializeWithFile() {
		try {
			Manager.setHint(Manager.LIGHTWEIGHT_RENDERER, (true));
			mySaveProcessor = Manager.createProcessor(((urlString)).toURI().toURL());
			mySaveProcessor.addControllerListener(this);
		}
		catch (NoPlayerException e) {
			e.printStackTrace();
		}
		catch (MalformedURLException e) {
			e.printStackTrace();
		}
		catch (IOException e) {
			e.printStackTrace();
		}
		mySaveProcessor.configure();
	}
	
	/**
	 * @author Michael Kascha 0548800
	 * set up the processor with an URL as source
	 */
	public void initializeWithURL() {
		try {
			Manager.setHint(Manager.LIGHTWEIGHT_RENDERER, (true));
			mySaveProcessor = Manager.createProcessor(urlSource);
			mySaveProcessor.addControllerListener(this);
		}
		catch (NoPlayerException e) {
			e.printStackTrace();
		}
		catch (MalformedURLException e) {
			e.printStackTrace();
		}
		catch (IOException e) {
			e.printStackTrace();
		}
		mySaveProcessor.configure();
	}
	
	/**
	 * @author Evelyn Koller 0300033, Michael Kascha 0548800
	 * deals with different types of events from ControllerListener
	 */
	public void controllerUpdate(ControllerEvent event) {
		if (event instanceof ConfigureCompleteEvent) {

			//set content descriptor to null to use processor as player
			FileTypeDescriptor myFileType = new FileTypeDescriptor(FileTypeDescriptor.QUICKTIME);
			mySaveProcessor.setContentDescriptor(myFileType);
			
			// Obtain the track controls.
			TrackControl tc[] = mySaveProcessor.getTrackControls();

			// Search for the track control for the video track.
			TrackControl videoTrack = null;

			for (int i = 0; i < tc.length; i++) {
			    if (tc[i].getFormat() instanceof VideoFormat) {
				videoTrack = tc[i];
				break;
			    }
			}

			// Make a codec chain to apply the effects to the video
			try {
			    Codec codec[] = { myEffect };
			    videoTrack.setCodecChain(codec);
			} catch (UnsupportedPlugInException e) {
			    System.err.println("Processor doesn't support effects");
			}
			
			mySaveProcessor.realize();
		}
		
		// actually save the video
		else if (event instanceof RealizeCompleteEvent) {
			System.out.println("Try to save video");
	        videoSource = mySaveProcessor.getDataOutput();
	        try {
				try {
					save = Manager.createDataSink(videoSource, savingPlace);
					save.addDataSinkListener(this);
				} catch (NoDataSinkException e) {
					e.printStackTrace();
				}
				//myEffect.setEffect(true);
				save.open();
		        save.start();
		        mySaveProcessor.start();
			} catch (IOException e) {
				e.printStackTrace();
			} 
			mySaveProcessor.prefetch();
		}
		
		else if (event instanceof PrefetchCompleteEvent) {
		}
		
		// EndOfMediaEvent
		else if(event instanceof EndOfMediaEvent) {
			mySaveProcessor.close();
			mySaveProcessor.stop();
		}
	}
	
	public void setProcessorEffect(boolean value) {
		myEffect.setEffect(value);
	}
	
	/**
	 * @author Evelyn Koller 0300033
	 * getter for receiving the duration of a video file
	 */
	public double getMediaDuration() {
		return mySaveProcessor.getDuration().getSeconds();
	}

	
	/**
	 * @author Evelyn Koller 0300033
	 * getter for receiving the actual time of a video file
	 * work in progress
	 */
	public double getMediaTime() {
		//while(giveVisualComponent == false) { }
		return mySaveProcessor.getMediaTime().getSeconds();
	}
	

	@Override
	public void dataSinkUpdate(DataSinkEvent dataSinkEvent) {
		if (dataSinkEvent instanceof EndOfStreamEvent) {
			if (save != null) {
				save.close();
			}
			//myEffect.setEffect(false);
			System.out.println("Finished saving");
		}
	}
}